/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package g360.WebXpdlValidation;

import java.io.*;

import java.util.ArrayList;
import java.util.Vector;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 *
 * @author andya
 */
public class ValidateXpdl extends HttpServlet implements ErrorHandler 
{
    private ResourceManager resources = new ResourceManager();
    private String formText = null;
    private String footerText = null;

    public ResourceManager getResourceManager()
    {
        return this.resources;
    }

    /** 
    * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
    * @param request servlet request
    * @param response servlet response
    */
    protected void processGetRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException 
    {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try 
        {
            outputHead(out);
            outputForm(out);
            outputTail(out);
        } 
        finally 
        { 
            out.close();
        }
    } 
    
    protected void outputHead(PrintWriter out)
    {
        out.println("<html>");
        out.println("<head>");
        out.println(Html.makeTag("title", getTitle()));
        out.println("<link rel=\"stylesheet\" type=\"text/css\" href=\"XpdlValidatorStyles.css\"/>");
        out.println("</head>");
        out.println("<body>");
 //       out.println(Html.makeTag("p","This is test #10."));
    }
    
    protected void outputFileList(PrintWriter out, String directoryName)
    {
        try
        {
            out.println(Html.makeTag("p", "Files in " + directoryName));
            File directory = new File(directoryName);
            File[] files = directory.listFiles();
            for (File file : files)
            {
                out.println(Html.makeTag("p", file.getAbsolutePath()));
            }
        }
        catch (Exception e)
        {
            out.println(Html.makeTag("p", e.getMessage()));
        }
    }

    protected void outputSystemProperties(PrintWriter out)
    {
        java.util.Properties p = System.getProperties();
        java.util.Enumeration keys = p.keys();
        String key = "catalina.home";
        String value = p.getProperty(key);
        while( keys.hasMoreElements() ) 
        {
            key = (String)keys.nextElement();
            value = p.getProperty(key);
            out.println("<p>" + key + "=" + value + "</p>");
        }
    }
    
    protected void outputForm(PrintWriter out)
    {
        out.println(Html.makeTag("h1", this.getTitle()));
        out.println(getFormText());
    }

    protected String getFormText()
    {
        if ((this.formText == null) || (this.formText.length() == 0))
        {
            this.formText = resources.getFormText();
        }
        return this.formText;
    }

    protected String getFooterText()
    {
        if ((this.footerText == null) || (this.footerText.length() == 0))
        {
            this.footerText = resources.getFooterText();
        }
        return this.footerText;
    }

    protected void outputTail(PrintWriter out)
    {
        out.println(Html.makeTag("p", Html.makeTag("a", "href=\"index.jsp\" class=\"webappname\" ", "Return to the introduction.")));
        out.println(this.getFooterText());
        out.println("</body>");
        out.println("</html>");
    }
    
    protected String extractControlValue(String controlName, String data, String defaultValue)
    {
        String result = null;
        String indexString = "Content-Disposition: form-data; name=\"" + controlName + "\"";
        int index = data.indexOf(indexString);
        try
        {
            if (index >= 0)
            {
                int start = data.indexOf("\n", index + indexString.length());
                start = data.indexOf("\n", start) + 1;
                start = data.indexOf("\n", start) + 1;
                int end = data.indexOf("\n", start);
                result = data.substring(start, end - 1);
            }
        }
        catch (Exception e)
        {
            // This catches any time we don't find what we are looking for.
        }
        if (result == null)
        {
            result = defaultValue;
        }
        return result;
    }
    
    protected void processPostRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException 
    {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        outputHead(out);

	//to get the content type information from JSP Request Header
	String contentType = request.getContentType();
	//here we are checking the content type is not equal to Null and as well as the passed data from mulitpart/form-data is greater than or equal to 0
	if ((contentType != null) && (contentType.indexOf("multipart/form-data") >= 0)) 
        {
            DataInputStream in = new DataInputStream(request.getInputStream());
            //we are taking the length of Content type data
            int formDataLength = request.getContentLength();
            byte dataBytes[] = new byte[formDataLength];
            int byteRead = 0;
            int totalBytesRead = 0;
            //this loop converting the uploaded file into byte code
            while (totalBytesRead < formDataLength) 
            {
                byteRead = in.read(dataBytes, totalBytesRead, formDataLength);
                totalBytesRead += byteRead;
            }

            String file = new String(dataBytes);
            String validationLevel = extractControlValue("Validation Level", file, "standard");
            String schemaVersion = extractControlValue("Schema Version", file, "2.1");
            String useG360Extensions = extractControlValue("UseG360Extensions", file, "off");
            String overrideFileSettings = extractControlValue("Override", file, "yes");
            boolean bOverrideFileSettings = overrideFileSettings.equalsIgnoreCase("yes");
            //for saving the file name
            String saveFile = file.substring(file.indexOf("filename=\"") + 10);
            saveFile = saveFile.substring(0, saveFile.indexOf("\n"));
            saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1,saveFile.indexOf("\""));
            boolean bInputIsEmpty = (saveFile.length() == 0);

            int lastIndex = contentType.lastIndexOf("=");
            String boundary = contentType.substring(lastIndex + 1,contentType.length());
            int pos;
            //extracting the index of file 
            pos = file.indexOf("filename=\"");
            pos = file.indexOf("\n", pos) + 1;
            pos = file.indexOf("\n", pos) + 1;
            pos = file.indexOf("\n", pos) + 1;
            int boundaryLocation = file.indexOf(boundary, pos) - 4;
            int startPos = ((file.substring(0, pos)).getBytes()).length;
            int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length;

            outputForm(out);
            
            out.println("<h2>Validator Results for " + saveFile +"</h2>");
            boolean bUseG360Extensions = false;
            if (bOverrideFileSettings)
            {
                out.println("<p>Schema Version: " + schemaVersion + "</p>");
                out.println(Html.makeTag("p", "Conformance class: " + validationLevel));
                bUseG360Extensions = false;
                if (useG360Extensions.equals("on"))
                {
                    out.println("<p>Using Global 360 Extensions.</p>");
                    bUseG360Extensions = true;
                }
            }
            else
            {
                out.println(Html.makeTag("p", "The XPDL file will be not be changed before validation."));
            }

            if (bInputIsEmpty)
            {
                out.println("<p>Input file is empty.</p>");
            }
            else
            {
                this.clearMessages();
                ByteArrayInputStream inputStream = new ByteArrayInputStream(dataBytes, startPos, (endPos - startPos));

                XpdlDomDocument xpdlDocument = this.makeDomXpdlDocument(inputStream);
                if (xpdlDocument == null)
                {
                    out.println(Html.makeTag("p", "The validater reported internal errors."));
                    listMessages(out);
                }
                else
                {
                    Vector<String> schemas = new Vector<String>();
                    if (bOverrideFileSettings)
                    {
                        xpdlDocument.setConformanceClass(validationLevel);
                        xpdlDocument.setDefaultNamespace(this.getSchemaURI(schemaVersion));
                        xpdlDocument.setXpdlNamespace(this.getSchemaURI(schemaVersion));
                        if (bUseG360Extensions)
                        {
                            xpdlDocument.setCustomNamespace("xmlns:g360", this.getG360SchemaURI(schemaVersion));
                        }
                        xpdlDocument.reparse();
                    }
                    schemas.add(resources.getSchemaFilePath("1.0"));
                    schemas.add(resources.getSchemaFilePath(schemaVersion));
                    if (bUseG360Extensions)
                    {
                        schemas.add(resources.getG360SchemaFilePath(schemaVersion));
                    }
                    ValidatorWrapper wrapper = new ValidatorWrapper(this);
                    boolean bCompleted = wrapper.validate(schemas, xpdlDocument, this);
                    if (bCompleted)
                    {
                        out.println("<p>The validater completed.</p>");
                        if (messages.size() == 0)
                        {
                            out.println("<p>There were no schema violations.</p>");
                        }
                        else
                        {
                            out.println("<p>The validator reported " + messages.size() + " schema violations:</p>");
                        }
                    }
                    else
                    {
                        out.println("<p>The validater reported internal errors.</p>");
                    }
                    listMessages(out);
                }
                
                
//		InputStreamReader reader = new InputStreamReader(inputStream);
//		BufferedReader bufferedReader = new BufferedReader(reader);
//		for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine())
//		{
//		    out.println("" + line + "<br/>");
//		}
                clearMessages();
                TransformWrapper transform = new TransformWrapper(this, schemaVersion);
                out.println(Html.makeTag("h2", "Transform Results"));
                if (transform.runTransform(xpdlDocument, out))
                {
                    out.println(Html.makeTag("p", "The transform completed."));
                }
                else
                {
                    out.println(Html.makeTag("p", "The transform reported internal errors."));
                }
                messages = transform.getMessages();
                if (messages.size() > 0)
                {
                    for (String message : messages)
                    {
                        out.println(message);
                    }
                }
            }

        }
        else
        {
            out.println("No data was recieved.");
        }
        outputTail(out);
        out.close();
    } 

    /** 
    * Handles the HTTP <code>GET</code> method.
    * @param request servlet request
    * @param response servlet response
    */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException 
    {
        processGetRequest(request, response);
    } 

    /** 
    * Handles the HTTP <code>POST</code> method.
    * @param request servlet request
    * @param response servlet response
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException 
    {
        processPostRequest(request, response);
    }
    
    public XpdlDomDocument makeDomXpdlDocument(InputStream source)
    {
        XpdlDomDocument result = null;
        try 
        {
            result = XpdlDomDocument.make(source, this);

        } 
        catch (IOException ioex)
        {
            reportException(ioex, "IO error");
        }
        catch (SAXException saxex)
        {
            reportException(saxex, "SAX error");
        }
        catch (ParserConfigurationException pex) 
        {
            reportException(pex, "Parser error");
        }
        catch (Exception ex)
        {
            reportException(ex, "Generic error");
        }
        return result;
    }

    //
    // ErrorHandler methods
    //

    /** Warning. */
    public void warning(SAXParseException ex) throws SAXException 
    {
    	appendErrorMessage("Warning", ex);
    } // warning(SAXParseException)

    /** Error. */
    public void error(SAXParseException ex) throws SAXException {
    	appendErrorMessage("Error", ex);
    } // error(SAXParseException)

    /** Fatal error. */
    public void fatalError(SAXParseException ex) throws SAXException {
    	appendErrorMessage("Fatal Error", ex);
        throw ex;
    } // fatalError(SAXParseException)
    
    /** Composes the error message. */
    protected void appendErrorMessage(String type, SAXParseException ex)
    {
    	this.appendMessage(composeErrorMessage(type, ex));
    }
    
    protected String composeErrorMessage(String type, SAXParseException ex) 
    {
    	String result = "";
        String systemId = ex.getSystemId();
        if (systemId != null) 
        {
            int index = systemId.lastIndexOf('/');
            if (index != -1)
                systemId = systemId.substring(index + 1);
        }
        else
        	systemId = "";
    	
    	result = "[" + type + "] " + systemId + ":" + ex.getLineNumber() + ":" + ex.getColumnNumber() + ": " + ex.getMessage();
    	return result;
    	
    } // composeErrorMessage(String,SAXParseException)
    
    protected void reportException(Exception ex, String messagePrefix)
    {
        String message = messagePrefix + " - " + ex.getMessage();
        this.appendMessage(message);
        System.err.println(message);
        if (ex instanceof SAXException) 
        {
            Exception se = ((SAXException)ex).getException();
            if (se != null) ex = se;
        }
        ex.printStackTrace(System.err);

    }

    private ArrayList<String> messages = new ArrayList<String>();
    
    public void clearMessages()
    {
    	this.messages.clear();
    }
    
    protected void appendMessage(String message)
    {
    	if (message != null)
    	{
            this.messages.add(message);
    	}
    }
    
    public ArrayList<String> getMessages()
    {
    	return this.messages;
    }
    
    public void listMessages(PrintWriter out)
    {
        if (messages.size() > 0)
        {
            out.println("<ol>");
            for (String message : messages)
            {
                out.println(Html.makeTag("li", message));
            }
            out.println("</ol>");
        }

    }
    //
    // HTML Generation
    //
    
    private String getTitle()
    {
        String title;
        String hostname = this.getHostName();
        if (hostname == null)
        {
            title = "XPDL Validation: Application";
        }
        else
        {
            title = "XPDL Validation: Application on " + hostname;
        }
        return title;
    }

    private String getHostName()
    {
        String result = null;
        result = System.getenv("HOSTNAME");
        result = System.getProperty("HOSTNAME");
        result = System.getProperties().getProperty("HOSTNAME");
        return result;
    }
    
    ValidatorProperties properties = null;
    
    private ValidatorProperties getProperties()
    {
        if (this.properties == null)
        {
            this.properties = new ValidatorProperties();
        }
        return this.properties;
    }
    
   
    protected String getG360SchemaURI(String xpdlVersion)
    {
        String result = null;
        result = "http://www.global360.com/XPDL2.0alpha";
        return result;
    }
    
    protected String getSchemaURI(String xpdlVersion)
    {
        String result = null;
        if (xpdlVersion.equals("2.0"))
        {
            result = "http://www.wfmc.org/2004/XPDL2.0alpha";
        }
        else
        {
            result = "http://www.wfmc.org/2008/XPDL2.1";
        }
        return result;
    }
    


    /** 
    * Returns a short description of the servlet.
    */
    public String getServletInfo() 
    {
        return "ValidateXpdl validates an XPDL file.";
    }



}
